package com.google.code.sprite.generate;

import org.apache.commons.io.FilenameUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.google.code.sprite.conf.TableConfig;
import com.google.code.sprite.util.Util;

public class DaoImplGenerate extends AbstractGenerate {

    public String getSubPackage() {
        return "dao.impl";
    }

    public void writeToFile(TableConfig tableConfig, TableMetaData tableMetaData) {
        init(tableConfig, tableMetaData);
        String subDir = getJavaSubPackagePath();
        String fileName = FilenameUtils.concat(subDir, daoImplClass+".java");
        writeToFile(fileName, generate());
    }

    public String generate() {
        File actionTemplate = getTemplateFile("DaoImpl.java");
        if (!actionTemplate.exists()) {
            return "";
        }
        String content = Util.readContent(actionTemplate);
        content = replaceVar(content);
        content = content.replace("${package}", pkg + ".dao.impl");

        content = content.replace("${mapperClass}", this.buildMapperClass());
        content = content.replace("${deleteMethod}", this.buildRemoveMethod());
        content = content.replace("${updateMethod}", this.buildUpdateMethod());
        content = content.replace("${addMethod}", this.buildInsertMethod());
        content = content.replace("${getMethod}", this.buildGetMethod());
        content = content.replace("${getListMethod}", this.buildGetListMethod());

        return content;
    }

    public String buildQueryMethod() {
        StringBuilder sb = new StringBuilder();
        String mapperClass = this.tableConfig.getEntityClassName()+"Mapper";
        sb.append(" public List query(String fieldName, String fieldValue) { \n");
        sb.append(" String sql = \"select * from ");
        sb.append(this.tableMetaData.getTableName());
        sb.append(" where \" + fieldName + \"='\" + fieldValue+\"';\"; \n");
        sb.append("return this.getJdbcTemplate().query(sql, new " + mapperClass+ "()); \n");
        sb.append("}\n");
        return sb.toString();
    }

    public String buildMapperClass() {
        StringBuilder sb = new StringBuilder();
        sb.append("class ");
        sb.append(this.tableConfig.getEntityClassName()+"Mapper");
        sb.append(" implements MultiRowMapper { \n ");
        sb.append(" public Object mapRow(ResultSet rs, int arg1) ");
        sb.append(" throws SQLException {  \n");
        sb.append( this.entityClass + " " + this.entityVar);
        sb.append(" = new " + this.entityClass + "(); \n");
        Map<String,ColumnMetaData> fields = tableMetaData.getFieldsInfo();
        for (String colName : fields.keySet()) {
            ColumnMetaData field = fields.get(colName);
            sb.append(this.entityVar + ".set");
            sb.append(Util.capatilize(field.normalizedName()));
            sb.append("(rs.get");
            sb.append(Util.capatilize(field.getJavaType()));
            sb.append("(\"" + field.getColumnName() + "\")); \n");
        }
        sb.append("return ").append(this.entityVar).append(";\n");
        sb.append("}\n");
        sb.append("}\n");
        return sb.toString();

    }

    public String buildRemoveMethod() {
        StringBuilder sb = new StringBuilder();
        sb.append("String sql=\"delete from ");
        sb.append(this.tableMetaData.getTableName());
        sb.append(" where id in (\" +  buildInParam(" + this.entityVar+"Ids) + \")\"; \n");
        sb.append(" this.getJdbcTemplate().update(sql); \n");
        sb.append(" return true ; \n");
        return sb.toString();
    }

    public String buildUpdateMethod() {
        StringBuilder sb = new StringBuilder();
        sb.append(this.getUpdateSQL());
        sb.append(" int changed = this.getJdbcTemplate().update(sql, ");
        sb.append(" new Object[] { \n" );
        Map<String,ColumnMetaData> fields = tableMetaData.getFieldsInfo();
        List<String> getters = new ArrayList<String>();
        for (String colName : fields.keySet()) {
            ColumnMetaData field = fields.get(colName);
            StringBuilder tmpSb = new StringBuilder();
            tmpSb.append(entityVar).append(".");
            tmpSb.append("get").append(Util.capatilize(field.normalizedName()));
            tmpSb.append("()");
            getters.add(tmpSb.toString());
        }
        List<String> lines = Util.fitToPrintWidth(getters, 70);
        for (String line : lines ) {
            sb.append(line).append("\n");
        }
        sb.deleteCharAt( sb.length() -1);
        sb.append(" }); \n");

        sb.append(" if (changed > 0) return true; \n ");
        sb.append(" return false; \n ");
                
        return sb.toString();
    }

    public String buildGetMethod() {
        StringBuilder sb = new StringBuilder();
        String mapperClass = this.tableConfig.getEntityClassName()+"Mapper";
        
        sb.append("String sql=\"select * from " + tableMetaData.getTableName()  + " where id=?\"; \n");
        sb.append("List list = query(sql, \n");
        sb.append("        new Object[] { " + entityVar + "Id }, \n");
        sb.append("        new " + mapperClass + "()); \n");
        sb.append("if (list == null || list.isEmpty()) { \n");
        sb.append("    return null; \n");
        sb.append("} else { \n");
        sb.append("    return ("+entityClass + ") list.get(0); \n");
        sb.append("} \n");
        return sb.toString();
    }

    public String buildGetListMethod() {
        StringBuilder sb = new StringBuilder();
        String mapperClass = this.tableConfig.getEntityClassName()+"Mapper";
        sb.append("String sql=\"select * from " + tableMetaData.getTableName()  + " where unitId=?\"; \n");
	    sb.append(" return query(sql, new Object[] { unitId }, \n");
        sb.append("new "+ mapperClass + "(), page); \n");
        return sb.toString();
    }

    public String buildInsertMethod() {
        StringBuilder sb = new StringBuilder();
        sb.append(getAddSQL());
        sb.append(" this.getJdbcTemplate().update(sql, ");
        sb.append(" new Object[] { \n" );

        Map<String,ColumnMetaData> fields = tableMetaData.getFieldsInfo();
        List<String> getters = new ArrayList<String>();
        for (String colName : fields.keySet()) {
            ColumnMetaData field = fields.get(colName);
            StringBuilder tmpSb = new StringBuilder();
            tmpSb.append(entityVar).append(".");
            tmpSb.append("get").append(Util.capatilize(field.normalizedName()));
            tmpSb.append("()");
            getters.add(tmpSb.toString());
        }
        List<String> lines = Util.fitToPrintWidth(getters, 70);
        for (String line : lines ) {
            sb.append(line).append("\n");
        }
        sb.deleteCharAt( sb.length() -1);
        sb.append(" }) ;\n");
        return sb.toString();
    }

    private String getAddSQL() {
        Map<String,ColumnMetaData> fields = tableMetaData.getFieldsInfo();
        StringBuffer sb = new StringBuffer();
        sb.append("String sql = \"INSERT INTO ");
        sb.append(tableMetaData.getTableName());
        sb.append("( \"\n");

        List<String> fieldNames = new ArrayList<String>();
        for (String colName :   fields.keySet()) {
            fieldNames.add(colName);
        }
        List<String> lines = Util.fitToPrintWidth(fieldNames, 60);
        for (String line : lines ) {
            sb.append(" + \" ").append(line).append(" \" \n");
        }

        sb.append(" + \" ) VALUES ( ");
        sb.append(Util.getQuestionMark(fields.size()));
        sb.append(")\";\n");

        return sb.toString();
    }
    private String getUpdateSQL() {
        Map<String,ColumnMetaData> fields = tableMetaData.getFieldsInfo();
        StringBuffer sb = new StringBuffer();
        sb.append("String sql = \"UPDATE ");
        sb.append(tableMetaData.getTableName());
        sb.append(" SET \"\n");

        List<String> params = new ArrayList<String>();
        for (String colName :   fields.keySet()) {
            params.add(colName + "=?");
        }
        List<String> lines = Util.fitToPrintWidth(params, 60);
        for (String line : lines ) {
            sb.append(" + \" ").append(line).append(" \" \n");
        }
        sb.deleteCharAt( sb.length() -1);
        sb.append("; \n");
        return sb.toString();
    }
    

}
